﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Infrastructure.ObjectModel;
using Infrastructure.ServiceInterfaces;
using B10_Ex02_Elad_034695114_Meyron_026607788;
using B10_Ex02_Elad_034695114_Meyron_026607788.ObjectModel;

namespace B10_Ex02_EladLebovitch_034695114.ObjectModel
{
    public class GameManager : GameService
    {
        #region Consts
        private const int k_MotherShipInterval = 15000;
        private const int k_SoulLossPenalty = 2200;
        private const int k_EnemyRows = 5;
        private const int k_EnemyCols = 9;
        private const int k_StartingSouls = 3;
        #endregion

        private double m_MotherShipTime;
        private int m_GameScore;
        private EnemyMatrix m_EnemiesMat;
        private MotherShip m_CurrMothership;
        private SpaceShip m_SpaceShip;
        private ICollisionDetector m_MyCollisionDetector;

        protected int GameScore
        {
            get
            {
                return m_GameScore;
            }

            set
            {
                m_GameScore = (int)MathHelper.Clamp((float)value, 0f, float.MaxValue);
            }
        }

        protected int Souls
        {
            get;
            set;
        }

        public bool IsGameOver
        {
            get;
            set;
        }
        
        public GameManager(Game i_game)
            : base(i_game)
        {           
        }

        /// <summary>
        /// Init method
        /// </summary>
        public override void Initialize()
        {
            // Init stuff
            base.Initialize();
            this.GameScore = 0;
            this.IsGameOver = false;
            this.Souls = k_StartingSouls;
            
            // Get collision detector
            m_MyCollisionDetector = this.Game.Services.GetService(typeof(ICollisionDetector)) as ICollisionDetector;
            
            // Create game objcets
            m_EnemiesMat = new EnemyMatrix(this.Game, k_EnemyCols, k_EnemyRows);
            m_SpaceShip = new SpaceShip(this.Game);
            
            // Handle the mother ship appearence
            this.m_MotherShipTime = 0;

            // Register Collision Detections
            m_MyCollisionDetector.RegisterCollisionCheck(
                m_SpaceShip,
                m_EnemiesMat.Bullets,
                new EventHandler<SpriteEventArgs>(spaceShipColieded));
            m_MyCollisionDetector.RegisterCollisionCheck(
                m_SpaceShip.Bullets,
                m_EnemiesMat.EnemiesList,
                new EventHandler<SpriteEventArgs>(enemyColieded));
        }

        /// <summary>
        /// Handles checks of the matrix
        /// </summary>
        private void handleMatrix()
        {
            // if the matrix got lower then spaceship
            if (this.m_EnemiesMat.LowerBoundery >= this.m_SpaceShip.Position.Y)
            {
                this.gameOver();
            }
        }

        /// <summary>
        /// The mothership creation method
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void handleMotherShip(GameTime gameTime)
        {
            this.m_MotherShipTime += gameTime.ElapsedGameTime.TotalMilliseconds;

            // Create a new mother ship
            if (this.m_MotherShipTime >= k_MotherShipInterval)
            {
                // if there is an old ship, Unregister it
                if (this.m_CurrMothership != null)
                {
                    this.m_MyCollisionDetector.UnRegisterCollisionCheck(this.m_CurrMothership, this.m_SpaceShip.Bullets);
                    this.m_CurrMothership.Distroy();
                }

                // Create and register new
                this.m_CurrMothership = new MotherShip(this.Game);
                this.m_MotherShipTime -= k_MotherShipInterval;
                this.m_MyCollisionDetector.RegisterCollisionCheck(
                    this.m_CurrMothership,
                    this.m_SpaceShip.Bullets,
                    new EventHandler<SpriteEventArgs>(MotherShipColieded));
            }
        }

        /// <summary>
        /// What happens if spaceship gets hit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void spaceShipColieded(object sender, SpriteEventArgs e)
        {
            (e.RelevantSprite as EnemyBullet).Distroy();
            this.m_SpaceShip.Position = new Vector2(0, this.m_SpaceShip.Position.Y);
            this.Souls--;
            this.GameScore -= k_SoulLossPenalty;

            // if no more souls
            if (Souls == 0)
            {
                this.gameOver();
            }
        }

        /// <summary>
        /// What happens if enemy gets hit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void enemyColieded(object sender, SpriteEventArgs e)
        {
            EnemySprite enemy = e.RelevantSprites.First(sprt => (sprt as EnemySprite) != null) as EnemySprite;
            PlayerBullet bullet = e.RelevantSprites.First(sprt => (sprt as PlayerBullet) != null) as PlayerBullet;
            m_EnemiesMat.KillEnemy(enemy);
            bullet.Distroy();
            this.GameScore += enemy.Points;
        }

        private void gameOver()
        {
            this.IsGameOver = true;
            MessageBox.Show("Game Over. \n Score: " + this.GameScore.ToString());
        }

        /// <summary>
        /// What happens if spaceship gets hit
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MotherShipColieded(object sender, SpriteEventArgs e)
        {
            (e.RelevantSprite as PlayerBullet).Distroy();
            (sender as MotherShip).Distroy();
            this.GameScore += (sender as MotherShip).Points;

            // Unregistering
            this.m_MyCollisionDetector.UnRegisterCollisionCheck((sender as MotherShip), this.m_SpaceShip.Bullets);

            // Clearing old mothership
            this.m_CurrMothership = null;
        }

        /// <summary>
        /// Update method for calcing the game
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            this.handleMotherShip(gameTime);
            this.handleMatrix();

            base.Update(gameTime);
        }
    }
}
